﻿' ------------------------------------------------------------------------------
' MetaMapper and MetaSpec provide a flexible means of associating
' together the image file metadata elements, their names, WIC queries,
' and the database columns used to store each element.
'
' MetaSpecs are created from a text file stored as a resource in
' the SpatialAlbum.Resources assembly. They are are used to determine
' how to query the metadata from image files (via a WIC query string)
' and which column to store the metadata element in in the database.
' 
' MetaSpecs are also used to create the Photo table which stores
' the metadata. The Photo table has columns added to it that
' are defined by column definitions stored in the resource file.
' Eventually, multiple metadata elements will be mapped to the same
' metadata element, and the column definitions should best be
' handled by some other mechanism.
' 
' This flexible scheme has been used since we will be
' developing/refining/changing the metadata elements that are accessed
' and stored for each photo as we develop code to support different metadata
' types defined by different standards. THis implementation is limited to 
' retrieving the GPS metadata supported by the Exif standard.
' ------------------------------------------------------------------------------
' This file is part of the SQL Server 2008 Technology Demonstration. This
' application was designed and coded by Eric Weitzman, LandTime Inc, for
' Microsoft Corporation. Contact Ed Katibah at Microsoft about this demo.
' Copyright © 2008 Microsoft Corporation. All rights reserved.
' ------------------------------------------------------------------------------

Public Structure MetaSpec

    Public WicQuery As String    ' Windows Imaging Component query string to retrieve element
    Public MetaName As String    ' element/property name
    Public ColumnName As String  ' name of the column in SQL Server
    Public ColumnSql As String   ' SQL fragment to define the column
    Public DecoderID As Integer  ' id used to choose decoder for the metadata
    ' -1 indicates that the element is derived from other elements
    Public Comment As String
    Public IsSparse As Boolean   ' parsed from ColumnSql

    Public Sub New(ByVal a() As String)
        Assert(a.Length = 6, "Metaspec.New: invalid argument")
        Initialize(a(0), a(1), a(2), a(3), a(4), a(5))
    End Sub
    Public Sub New(ByVal wic As String, ByVal name As String, ByVal colname As String, ByVal coldef As String, ByVal decode As String, ByVal cmt As String)
        Initialize(wic, name, colname, coldef, decode, cmt)
    End Sub
    Private Sub Initialize(ByVal wic As String, ByVal name As String, ByVal colname As String, ByVal colsql As String, ByVal decode As String, ByVal cmt As String)
        WicQuery = wic.Trim
        MetaName = name.Trim
        ColumnName = colname.Trim
        ColumnSql = colsql.Trim
        DecoderID = Integer.Parse(decode.Trim)
        Comment = cmt.Trim

        Dim words() As String = ColumnSql.ToLower.Split(" "c)
        For Each word As String In words
            If word = "sparse" Then
                IsSparse = True
                Exit For
            End If
        Next
    End Sub
End Structure

Public Class MetaMapper
    Public MetaSpecs As Dictionary(Of String, MetaSpec)

    Public Sub New(ByVal mappings As String)
        MetaSpecs = New Dictionary(Of String, MetaSpec)
        Load(mappings)
    End Sub

    Private Sub Load(ByVal mappings As String)
        For Each s As String In mappings.Split(vbCrLf.ToCharArray())
            s = s.Trim
            If s.Length <> 0 And Not s.StartsWith("#"c) Then
                Try
                    Dim a() As String = s.Split(";"c)
                    Dim spec As New MetaSpec(a)
                    MetaSpecs.Add(spec.MetaName, spec)
                Catch ex As Exception
                    ReportException(New ArgumentException("Invalid data: " & s, ex))
                End Try
            End If
        Next
    End Sub

    Public Function IsSparse(ByVal colname As String) As Boolean
        For Each meta As MetaSpec In MetaSpecs.Values
            If meta.ColumnName.ToLower = colname.ToLower Then Return meta.IsSparse
        Next
        Return False
    End Function

End Class
